﻿/* 
 * Copyright (c) 2008 Intel Corporation
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * -- Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * -- Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * -- Neither the name of the Intel Corporation nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE INTEL OR ITS
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

using System;
using System.Collections.Generic;
using ExtensionLoader;
using ExtensionLoader.Config;
using OpenMetaverse;

namespace AssetServer.Extensions
{
    [Flags]
    enum Permissions
    {
        Read = 1,
        Write = 2,
    }

    public class AuthorizeWhitelist : IExtension<AssetServer>, IAuthorizationProvider
    {
        AssetServer server;
        Dictionary<Uri, Permissions> whitelist = new Dictionary<Uri, Permissions>();

        public AuthorizeWhitelist()
        {
        }

        public bool Start(AssetServer server)
        {
            this.server = server;

            whitelist = new Dictionary<Uri, Permissions>();

            try
            {
                IConfig whitelistConfig = server.ConfigFile.Configs["AuthorizeWhitelist"];
                string[] entries = whitelistConfig.GetKeys();

                for (int i = 0; i < entries.Length; i++)
                {
                    string entry = entries[i];
                    string permString = whitelistConfig.GetString(entry);

                    Permissions perms = 0;
                    if (permString.Contains("R"))
                        perms |= Permissions.Read;
                    if (permString.Contains("W"))
                        perms |= Permissions.Write;

                    whitelist[new Uri(entry)] = perms;
                }
            }
            catch (Exception)
            {
                Logger.Log.Error("Failed to load [AuthorizeWhitelist] section from config file " + AssetServer.CONFIG_FILE);
            }
            return true;
        }

        public void Stop()
        {
        }

        public bool IsMetadataAuthorized(UUID authToken, UUID assetID)
        {
            Uri identifier;
            if (server.AuthenticationProvider.TryGetIdentifier(authToken, out identifier))
            {
                foreach (KeyValuePair<Uri, Permissions> kvp in whitelist)
                {
                    if (Match(identifier, kvp.Key) && (kvp.Value & Permissions.Read) != 0)
                        return true;
                }
            }
            
            return false;
        }

        public bool IsDataAuthorized(UUID authToken, UUID assetID)
        {
            Uri identifier;
            if (server.AuthenticationProvider.TryGetIdentifier(authToken, out identifier))
            {
                foreach (KeyValuePair<Uri, Permissions> kvp in whitelist)
                {
                    if (Match(identifier, kvp.Key) && (kvp.Value & Permissions.Read) != 0)
                        return true;
                }
            }

            return false;
        }

        public bool IsCreateAuthorized(UUID authToken)
        {
            Uri identifier;
            if (server.AuthenticationProvider.TryGetIdentifier(authToken, out identifier))
            {
                foreach (KeyValuePair<Uri, Permissions> kvp in whitelist)
                {
                    if (Match(identifier, kvp.Key) && (kvp.Value & Permissions.Write) != 0)
                        return true;
                }
            }

            return false;
        }

        public bool IsInventoryReadAuthorized(UUID authToken, Uri owner)
        {
            Uri identifier;
            if (server.AuthenticationProvider.TryGetIdentifier(authToken, out identifier))
            {
                foreach (KeyValuePair<Uri, Permissions> kvp in whitelist)
                {
                    if (Match(identifier, kvp.Key) && (kvp.Value & Permissions.Read) != 0)
                        return true;
                }
            }

            return false;
        }

        public bool IsInventoryWriteAuthorized(UUID authToken, Uri owner)
        {
            Uri identifier;
            if (server.AuthenticationProvider.TryGetIdentifier(authToken, out identifier))
            {
                foreach (KeyValuePair<Uri, Permissions> kvp in whitelist)
                {
                    if (Match(identifier, kvp.Key) && (kvp.Value & Permissions.Write) != 0)
                        return true;
                }
            }

            return false;
        }

        bool Match(Uri identifier, Uri comparer)
        {
            return ((comparer.PathAndQuery == "/" || comparer.PathAndQuery == identifier.PathAndQuery) && comparer.Host == identifier.Host);
        }
    }
}
